#!/user/bin/env python
# -*- coding: utf-8 -*-
''' 
Author: Sjy
LastEditTime: 2024-12-16 16:24:42
Description: 根据数据生成表单输入窗口 
根据json数据自动生成对应widget
TODO: 考虑一行多个widget的情况
'''

__all__= []

import sys
from PyQt5 import QtWidgets, QtGui, QtCore
from abc import ABCMeta,abstractmethod

try:
    from .util_file import import_custom_type_file
    from ..controls.apis import open_vtk
except:
    from util_file import import_custom_type_file

global TYPE_CONFIG
TYPE_CONFIG = {
    "space": 10,
    "margin": [0, 0, 0, 0],
}

class RequiredValidator(QtGui.QValidator):
    def validate(self, input_str, pos):
        if input_str.strip():  # 检查输入是否为空
            return (QtGui.QValidator.Acceptable, input_str, pos)
        else:
            return (QtGui.QValidator.Intermediate, input_str, pos)
class _UiBase(QtWidgets.QWidget):
    """负责整理 UI 布局
    """
    def __init__(self, data:dict={}) -> None:
        """初始化
        Args:
            data (dict, optional): 配置数据. Defaults to None.
        Return:
            None
        """
        super(_UiBase, self).__init__()
        self._widget = None # 记录用于实例化的 widget
        self.__data = data  # 缓存数据信息
        self.__init_layout()
    def __init_layout(self) -> None:
        """初始化布局,当前仅处理水平布局
        Args:
            无
        Return:
            None
        """
        styleParams = self.__data.get('styleParams', {})
        curMargin = styleParams.get('margin', TYPE_CONFIG.get("margin"))
        curSpace = styleParams.get('space', TYPE_CONFIG.get("space"))
        layout = QtWidgets.QHBoxLayout()
        if curMargin != None:
            layout.setContentsMargins(*curMargin)
        if curSpace != None:
            layout.setSpacing(curSpace)
        
        
        onCustomLayout = self.__data.get('onCustomLayout', None)
        if onCustomLayout and isinstance(onCustomLayout, type(lambda:0)):
            """如果存在自定义布局 则优先使用自定义布局 会将layout 传入"""
            onCustomLayout(layout)
        else:
            """调用接口函数（需要子类实例化的）用于处理展示每行的信息"""
            self._init_layout_widgets(layout)
            # 除了自定义布局 还允许传入补充组件 就是在原有类型widget 后面追加组件 跟 file 类似相当于 text 追加了一个btn
            onLayoutAppendWidget = self.__data.get('onLayoutAppendWidget', None)
            if onLayoutAppendWidget and isinstance(onLayoutAppendWidget, type(lambda:0)):
                onLayoutAppendWidget(layout)

        self.setLayout(layout)
    # 接口函数
    @abstractmethod 
    def _init_layout_widgets(self, layout:QtWidgets.QHBoxLayout=None) -> None:
        """初始化当前布局下的 widgets
        Return:
            value (any, optional): 返回的数据. Defaults to "".
        """
        pass
    @abstractmethod 
    def _get(self) -> any:
        """获取数据
        Return:
            value (any, optional): 返回的数据. Defaults to "".
        """
        pass
    @abstractmethod 
    def _set(self, value:any=None) -> None:
        """设置数据
        Args:
            value (str, optional): 传入的数据. Defaults to "".
        """
    def _get_params(self) -> None:
        """获取参数
        Args:
            无
        Return:
            None
        """
        return self.__data
    def _init_label_style(self, label:QtWidgets.QLabel=None) -> None: 
        """初始化标题的样式，这里可以统一设置
        Args:
            label (QtWidgets.QLabel, optional): 左侧标题. Defaults to None.
        Return:
            None
        """
        if not label:return 
        styleParams = self.__data.get('styleParams', {})
        labWidth = styleParams.get('labWidth', TYPE_CONFIG.get("labWidth"))
        if labWidth:
            label.setFixedWidth(labWidth)
    def _init_widget_style(self, widget:QtWidgets.QWidget=None) -> None: 
        """_summary_
        Args:
            label (QtWidgets.QLabel, optional): _description_. Defaults to None.
        """
        if not widget:return 
        styleParams = self.__data.get('styleParams', {})
        typeParams = self.__data.get('typeParams', {})
        minWidth = styleParams.get('minWidth', TYPE_CONFIG.get("minWidth"))
        if minWidth:
            widget.setMinimumWidth(minWidth)
        maxWidth = styleParams.get('maxWidth', TYPE_CONFIG.get("maxWidth"))
        if maxWidth:
            widget.setMaximumWidth(maxWidth)
        widget.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
        mustInput = typeParams.get('must', self.__data.get("must", False))
        if mustInput:
            print("设置必填验证器")
            widget.setValidator(RequiredValidator())  # 设置必填验证器
    def _init_layout_label(self, layout:QtWidgets.QHBoxLayout=None) -> None:
        """初始化标题
        Args:
            无
        Return:
            None
        """
        data = self._get_params()
        typeParams = data.get('typeParams', {})
        # 检查必填项
        mustInput = typeParams.get('must', data.get("must", False))
        title = typeParams.get('title', data.get("title", ""))
        lable = QtWidgets.QLabel()
        if mustInput:
            lable.setText(f"{title} <font style='color:red;font-weight:bolder'>*</font>")
        else:
            lable.setText(title)
        self._init_label_style(lable)
        layout.addWidget(lable)
# lineEdit ========================================
class _UiTypeText(_UiBase):
    def __init__(self, *args, **kwargs) -> None:
        """初始化
        Args:
            parent (QtWidgets.QWidget, optional): 主界面对象. Defaults to None.
        Return:
            None
        """
        self._widget = None # 记录用于实例化的 widget
        super(_UiTypeText, self).__init__(*args, **kwargs)
    def _init_layout_widgets(self, layout:QtWidgets.QHBoxLayout=None) -> None:
        """初始化当前行布局内容对象
        Args:
            layout (QtWidgets.QHBoxLayout, optional): 布局对象. Defaults to None.
        Return:
            None
        """
        self._init_layout_label(layout)
        self._init_layout_text(layout)
    def _init_layout_text(self, layout:QtWidgets.QHBoxLayout=None) -> None:
        """初始化文本框
        Args:
            无
        Return:
            None
        """
        data = self._get_params()
        typeParams = data.get('typeParams', {})
        readOnly = typeParams.get('readOnly', False)
        placeholder = typeParams.get('placeholder', "")
        lineEdit = QtWidgets.QLineEdit()
        if placeholder:
            lineEdit.setPlaceholderText(placeholder)
        # 默认开启删除按钮
        if not readOnly:
            lineEdit.setClearButtonEnabled(True)
        else:
            lineEdit.setReadOnly(True)

        self._init_widget_style(lineEdit)
        layout.addWidget(lineEdit)
        self._widget = lineEdit
    def _get(self) -> any:
        """获取数据
        Args:
            无
        Return:
            value (any, optional): 返回的数据. Defaults to "".
        """
        return self._widget.text()
    def _set(self, value:str=""):
        """设置数据
        Args:
            value (str, optional): 传入的数据. Defaults to "".
        """
        self._widget.setText(str(value))
    def _get_widget(self):
        """获取当前的widget
        Args:
            无
        Return:
            widget (QtWidgets.QWidget, optional): 返回的widget. Defaults to None.
        """
        return self._widget
class _UiTypeFile(_UiTypeText):
    def __init__(self, *args, **kwargs) -> None:
        """初始化
        Args:
            data (dict, optional): 配置数据. Defaults to None.
        Return:
            None
        """
        super(_UiTypeFile, self).__init__(*args, **kwargs)
    def _init_layout_widgets(self, layout:QtWidgets.QHBoxLayout=None) -> None:
        """初始化当前行布局内容对象
        Args:
            layout (QtWidgets.QHBoxLayout, optional): 布局对象. Defaults to None.
        Return:
            None
        """
        self._init_layout_label(layout)
        self._init_layout_text(layout)
        self.__init_layout_select(layout)
    def __init_layout_select(self, layout:QtWidgets.QHBoxLayout=None) -> None:
        data = self._get_params()
        typeParams = data.get('typeParams', {})
        fileType = typeParams.get('fileType', "")
        btnSelect = QtWidgets.QPushButton(" ... ")
        btnSelect.clicked.connect(lambda *args, fileType=fileType: self._on_select_file(fileType))
        # 设置 btnSelect 默认没有焦点
        btnSelect.setFocusPolicy(QtCore.Qt.NoFocus)
        layout.addWidget(btnSelect)
    def _on_select_file(self, fileType:str=""):
        fileInfo = import_custom_type_file(fileType, file=self._get(), parent=self)
        if fileInfo:
            file = fileInfo.get('file', '')
            self._widget.setText(file)
            typeParams = self._get_params().get('typeParams', {})
            onSelected = typeParams.get('onSelected', None)
            if onSelected and isinstance(onSelected, type(lambda:0)):
                onSelected(file)


class _UiTypeInt(_UiTypeText):
    def __init__(self, *args, **kwargs) -> None:
        """初始化
        Args:
            parent (QtWidgets.QWidget, optional): 主界面对象. Defaults to None.
        Return:
            None
        """
        super(_UiTypeInt, self).__init__(*args, **kwargs)

        widget = self._get_widget()
        widget.setValidator(QtGui.QIntValidator())
        
    def _get(self) -> any:
        """获取数据
        Args:
            无
        Return:
            value (any, optional): 返回的数据. Defaults to "".
        """
        widget = self._get_widget()
        value = widget.text()
        if value == "":
            return None
        else:
            return int(value)
    def _set(self, value:int=None):
        """设置数据
        Args:
            value (str, optional): 传入的数据. Defaults to "".
        """
        value = value if value != None else ""
        self._widget.setText(str(value))
class _UiTypeFloat(_UiTypeText):
    def __init__(self, *args, **kwargs) -> None:
        """初始化
        Args:
            parent (QtWidgets.QWidget, optional): 主界面对象. Defaults to None.
        Return:
            None
        """
        super(_UiTypeFloat, self).__init__(*args, **kwargs)
        widget = self._get_widget()
        widget.setValidator(QtGui.QDoubleValidator())
    def _get(self) -> any:
        """获取数据
        Args:
            无
        Return:
            value (any, optional): 返回的数据. Defaults to "".
        """
        widget = self._get_widget()
        value = widget.text()
        if value == "":
            return None
        else:
            return float(value)
    def _set(self, value:int=None):
        """设置数据
        Args:
            value (str, optional): 传入的数据. Defaults to "".
        """
        value = value if value != None else ""
        self._widget.setText(str(value))
# combobox  ========================================
class _UiTypeSelect(_UiBase):
    def __init__(self, *args, **kwargs) -> None:
        """初始化
        Args:
            data (dict, optional): 配置数据. Defaults to None.
        Return:
            None
        """
        self._widget = None # 记录用于实例化的 widget
        super(_UiTypeSelect, self).__init__(*args, **kwargs)
    def _init_layout_widgets(self, layout:QtWidgets.QHBoxLayout=None) -> None:
        """初始化当前行布局内容对象
        Args:
            layout (QtWidgets.QHBoxLayout, optional): 布局对象. Defaults to None.
        Return:
            None
        """
        self._init_layout_label(layout)
        self._init_layout_select(layout)

    def _init_layout_select(self, layout:QtWidgets.QHBoxLayout=None) -> None:
        """初始化下拉框
        Args:
            无
        Return:
            None
        """
        data = self._get_params()
        typeParams = data.get('typeParams', {})
        data = typeParams.get('data', []) # 下拉框的数据
        """_summary_
        data = [
            {"title": "title1", "value": "value1"},
            {"title": "title2", "value": "value2"},
        ]
        """
        comboBox = QtWidgets.QComboBox()
        # 设置 combox 水平方向上按容器大小扩展
        comboBox.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
        self._widget = comboBox
        self._set_items(data)
        self._init_widget_style(comboBox)
        layout.addWidget(comboBox)

    def _get(self) -> any:
        """获取数据
        Args:
            无
        Return:
            value (any, optional): 返回的数据. Defaults to "".
        """
        value = self._widget.currentData(QtCore.Qt.UserRole)
        if value != None: return value
        return self._widget.currentText()
    def _set(self, value:any=""):
        """设置数据
        Args:
            value (any, optional): 传入的数据. Defaults to "".
        """
        index = self._widget.findData(value, QtCore.Qt.UserRole)
        if index != None and index >= 0:
            return self._widget.setCurrentIndex(index)
        self._widget.setCurrentIndex(0)
    def _set_items(self, data:list=[], append:bool=False) -> None:
        """设置下拉框的数据
        Args:
            items (list, optional): 数据列表. Defaults to [].
        """
        typeParams = self._get_params().get('typeParams', {})
        if not append:
            self._widget.clear()
            hasDefaultOption = typeParams.get('hasDefaultOption', False)
            if hasDefaultOption:
                self._widget.addItem(hasDefaultOption if hasDefaultOption !=True and isinstance(hasDefaultOption, str) else "", "")
        for item in data:
            if isinstance(item, str):
                self._widget.addItem(item)
            elif isinstance(item, dict):
                self._widget.addItem(item.get("title"), item.get("value"))

# checkbox  ========================================
class _UiTypeCheckbox(_UiBase):
    def __init__(self, *args, **kwargs) -> None:
        """初始化
        Args:
            data (dict, optional): 配置数据. Defaults to None.
        Return:
            None
        """
        self._widget = None # 记录用于实例化的 widget
        super(_UiTypeCheckbox, self).__init__(*args, **kwargs)
    def _init_layout_widgets(self, layout:QtWidgets.QHBoxLayout=None) -> None:
        """初始化当前行布局内容对象
        Args:
            layout (QtWidgets.QHBoxLayout, optional): 布局对象. Defaults to None.
        Return:
            None
        """
        self._init_layout_label(layout)
        self._init_layout_checkbox(layout)
    def _init_layout_checkbox(self, layout:QtWidgets.QHBoxLayout=None) -> None:
        """初始化复选框
        Args:
            无
        Return:
            None
        """
        data = self._get_params()
        typeParams = data.get('typeParams', {})
        title = typeParams.get('checkTitle', "")
        if title:
            checkbox = QtWidgets.QCheckBox(title)
        else:
            checkbox = QtWidgets.QCheckBox()
        checkbox.setFocusPolicy(QtCore.Qt.NoFocus)
        self._init_widget_style(checkbox)
        layout.addWidget(checkbox)
        layout.addStretch(1)
        checkbox.setStyleSheet("QCheckBox:hover { text-decoration: none; }")
        self._widget = checkbox
    def _get(self) -> any:
        """获取数据
        Args:
            无
        Return:
            value (any, optional): 返回的数据. Defaults to "".
        """
        return self._widget.isChecked()
    def _set(self, value:bool=False):
        """设置数据
        Args:
            value (str, optional): 传入的数据. Defaults to "".
        """
        self._widget.setChecked(value)
class WidgetGroupRadios(QtWidgets.QWidget):
    def __init__(self, parent=None, params:dict={}):
        super(WidgetGroupRadios, self).__init__(parent)
        
        self.__params = params
        self.__radios = {} # 记录value 对应的radio button
        self.__init_layout()
    def __init_layout(self) -> None:
        """初始化布局,当前仅处理水平布局
        Args:
            无
        Return:
            None
        """
        typeParams = self.__params.get('typeParams', {})
        onChanged = typeParams.get('onChanged', None)
        data = typeParams.get('data', []) # 下拉框的数据
        """_summary_
        data = [
            {"title": "title1", "value": "value1"},
            {"title": "title2", "value": "value2"},
        ]
        """
        buttonGroup = QtWidgets.QButtonGroup(self)
        if onChanged and isinstance(onChanged, type(lambda:0)):
            buttonGroup.buttonClicked.connect(lambda btn, *args: onChanged(self.__get_value(btn)))
        layoutRadio = QtWidgets.QHBoxLayout(self)
        layoutRadio.addStretch(1)
        for item in data:
            if isinstance(item, str):
                radioButton = QtWidgets.QRadioButton(item)
            elif isinstance(item, dict):
                radioButton = QtWidgets.QRadioButton(item.get("title"))

            self.__radios[item.get("value")] = radioButton
            buttonGroup.addButton(radioButton)
            # self._init_widget_style(radioButton)
            layoutRadio.addWidget(radioButton)
            layoutRadio.addStretch(1)

            # 设置没有焦点
            radioButton.setFocusPolicy(QtCore.Qt.NoFocus)
            # 设置鼠标悬停样式
            radioButton.setStyleSheet("QRadioButton:hover { text-decoration: none; }")
        

    def _get(self) -> any:
        """获取数据
        Args:
            无
        Return:
            value (any, optional): 返回的数据. Defaults to "".
        """
        print(".._get", self.__radios)
        for value, radio in self.__radios.items():
            print(value, radio.isChecked())
            if radio.isChecked():
                return value
    def _set(self, value:str=""):
        """设置数据
        Args:
            value (str, optional): 传入的数据. Defaults to "".
        """
        for v, radio in self.__radios.items():
            radio.setChecked(v == value)

    def __get_value(self, btn:QtWidgets.QRadioButton):
        """获取当前选中的值
        Args:
            btn (QtWidgets.QRadioButton, optional): 选中的按钮. Defaults to None.
        Return:
            value (any, optional): 返回的数据. Defaults to "".
        """
        for value, radio in self.__radios.items():
            if radio == btn:
                return value
        return None
# radios  ========================================
class _UiTypeRadios(_UiBase):
    def __init__(self, *args, **kwargs) -> None:
        """初始化
        Args:
            data (dict, optional): 配置数据. Defaults to None.
        Return:
            None
        """
        self._widget = None # 记录用于实例化的 widget
        super(_UiTypeRadios, self).__init__(*args, **kwargs)
    def _init_layout_widgets(self, layout:QtWidgets.QHBoxLayout=None) -> None:
        """初始化当前行布局内容对象
        Args:
            layout (QtWidgets.QHBoxLayout, optional): 布局对象. Defaults to None.
        Return:
            None
        """
        self._init_layout_label(layout)
        self._init_layout_radios(layout)
    def _init_layout_radios(self, layout:QtWidgets.QHBoxLayout=None) -> None:
        """初始化多个单选框
        Args:
            layout (QtWidgets.QHBoxLayout, optional): 布局对象. Defaults to None.
        Return:
            None
        Description:
            因为存在多个radio组件因此用一个widget 将所有的radio 包装一下 这样就可以统一处理
        """
        self._widget = WidgetGroupRadios(self, self._get_params())
        layout.addWidget(self._widget)
    def _get(self) -> any:
        """获取数据
        Args:
            无
        Return:
            value (any, optional): 返回的数据. Defaults to "".
        """
        return self._widget._get()
    def _set(self, value:str=""):
        """设置数据
        Args:
            value (str, optional): 传入的数据. Defaults to "".
        """
        return self._widget._set(value)
# separator  ========================================
class _UiTypeSeparator(_UiBase):
    def __init__(self, *args, **kwargs) -> None:
        """初始化
        Args:
            data (dict, optional): 配置数据. Defaults to None.
        Return:
            None
        """
        super(_UiTypeSeparator, self).__init__(*args, **kwargs)
    def _init_layout_widgets(self, layout:QtWidgets.QHBoxLayout=None) -> None:
        """初始化当前行布局内容对象
        Args:
            layout (QtWidgets.QHBoxLayout, optional): 布局对象. Defaults to None.
        Return:
            None
        """
        separator = QtWidgets.QFrame()
        separator.setFrameShape(QtWidgets.QFrame.HLine)
        separator.setFrameShadow(QtWidgets.QFrame.Sunken)
        layout.addWidget(separator)
# btns  ========================================
class _UiTypeTools(QtWidgets.QWidget):
    def __init__(self, data:dict={}) -> None:
        """初始化
        Args:
            data (dict, optional): 配置数据. Defaults to None.
        Return:
            None
        """
        super(_UiTypeTools, self).__init__()
        self.__data = data
        
        self.__init_layout()
    def __init_layout(self) -> None:
        """初始化布局,当前仅处理水平布局
        Args:
            无
        Return:
            None
        """
        styleParams = self.__data.get('styleParams', {})
        curMargin = styleParams.get('margin', TYPE_CONFIG.get("margin"))
        curSpace = styleParams.get('space', TYPE_CONFIG.get("space"))
        layout = QtWidgets.QHBoxLayout()
        if curMargin != None:
            layout.setContentsMargins(*curMargin)
        if curSpace != None:
            layout.setSpacing(curSpace)
        # 调用接口函数（需要子类实例化的）用于处理展示每行的信息
        self.__init_layout_widgets(layout)
        self.setLayout(layout)
    def __init_layout_widgets(self, layout:QtWidgets.QHBoxLayout=None) -> None:
        """初始化当前行布局内容对象
        Args:
            layout (QtWidgets.QHBoxLayout, optional): 布局对象. Defaults to None.
        Return:
            None
        """
        data = self.__data
        typeParams = data.get('typeParams', {})
        btns = typeParams.get('items', [])
        

        layout.setAlignment(QtCore.Qt.AlignCenter)
        # layout.addStretch(1)
        for btn in btns:
            pbtn = QtWidgets.QPushButton(btn.get('title', ''))
            objectName = btn.get('objectName', '')
            if objectName:
                pbtn.setObjectName(objectName)
            action = btn.get('action', None)
            if action:
                pbtn.clicked.connect(lambda *args, action=action:action())
            layout.addWidget(pbtn)
            
        self.setObjectName("uiCustomFormTools")

class _UiTypeVtkFile(_UiTypeFile):
    def __init__(self, *args, **kwargs) -> None:
        super(_UiTypeVtkFile, self).__init__(*args, **kwargs)
    def _init_layout_widgets(self, layout:QtWidgets.QHBoxLayout=None) -> None:
        """初始化当前行布局内容对象
        Args:
            layout (QtWidgets.QHBoxLayout, optional): 布局对象. Defaults to None.
        Return:
            None
        """
        super(_UiTypeVtkFile, self)._init_layout_widgets(layout)
        self._init_layout_render_vtk(layout)

    def _on_select_file(self, fileType:str=""):
        """重写选择文件的方法 固定的 fileType 类型"""
        fileInfo = import_custom_type_file("VTK Files (*.vtk)", file=self._get(), parent=self)
        if fileInfo:
            file = fileInfo.get('file', '')
            self._widget.setText(file)
            typeParams = self._get_params().get('typeParams', {})
            onSelected = typeParams.get('onSelected', None)
            if onSelected and isinstance(onSelected, type(lambda:0)):
                onSelected(file)
                

    def _init_layout_render_vtk(self, layout:QtWidgets.QHBoxLayout=None) -> None:
        """初始化渲染vtk文件的组件"""
        data = self._get_params()
        typeParams = data.get('typeParams', {})
        btnSelect = QtWidgets.QPushButton("显示模型")
        btnSelect.clicked.connect(lambda *args: self._on_show_vtk())
        # 设置 btnSelect 默认没有焦点
        btnSelect.setFocusPolicy(QtCore.Qt.NoFocus)
        layout.addWidget(btnSelect)
    def _on_show_vtk(self):
        """显示vtk文件"""
        file = self._get()
        if file:
            open_vtk(file)
        else:
            raise Exception("文件不存在")

# 外部使用组件
class UiCustomForm(QtWidgets.QWidget):
    __TYPES = {
        'text': _UiTypeText, 
        'separator': _UiTypeSeparator,
        'int': _UiTypeInt,
        'float': _UiTypeFloat,
        'select': _UiTypeSelect,
        'checkbox': _UiTypeCheckbox,
        'file': _UiTypeFile,
        'vtkFile': _UiTypeVtkFile,
        'tools': _UiTypeTools,
        'radios': _UiTypeRadios, # 多个单选框
    }
    def __init__(self, data:dict={}, *args, parent=None, **kwargs) -> None:
        """初始化
        Args:
            data (dict, optional): 生成界面ui的数据. Defaults to {}.
        Return:
            None
        """
        super(UiCustomForm, self).__init__(parent)
        self.__data = data
        self.__parent = parent
        self.__uis = {} # 保存所有的widget 根据objectName 确定 映射ui关系 {key:ui}
        self.__qLayout = self.__get_window_layout()
        # self.setLayout(self.__qLayout)
        self.__init_form_items(self.__qLayout)
        self.setLayout(self.__qLayout)


    def _get_layout(self) -> None:
        """设置布局
        Args:
            qLayout (QtWidgets.QWidget, optional): 布局对象. Defaults to None.
        Return:
            None
        """
        return self.__qLayout

    def _setup_ui(self, parent:QtWidgets.QDialog=None) -> None:
        """为主界面设置ui
        Args:
            parent (QtWidgets.QDialog, optional):主界面的对象. Defaults to {}.
        Return:
            None
        """
        self.__parent = parent
        self.__init_window_config()
        self.__parent.setLayout(self.__qLayout)
    # def _gets(self) -> dict:
    #     """获取所有的数据
    #     Args:
    #         无
    #     Return:
    #         dict: 返回所有的数据
    #     """
    #     removeEmpty = self.__data.get('removeEmpty', False)
    #     data = {}
    #     for key, ui in self.__uis.items():
    #         if hasattr(ui, "_get"):
    #             value = ui._get()
    #             if not removeEmpty or (value !="" and value != None):
    #                 data[key] = value
    #     return {
    #         "data":data,
    #         "delKeys":[],
    #     }
    def _gets(self) -> dict:
        """获取所有的数据, 注意返回的数据中的data 属性对应的是所有的数据，delKeys 是删除的key列表
        Args:
            无
        Return:
            dict: 返回所有的数据
        """
        removeEmpty = self.__data.get('removeEmpty', False)
        delKeys = []
        data = {}
        for key, ui in self.__uis.items():
            if hasattr(ui, "_get"):
                value = ui._get()
                # print("value", key, value)
                if not removeEmpty or (value !="" and value != None):
                    data[key] = value
                else:
                    delKeys.append(key)
        return {
            "data": data,
            "delKeys": delKeys,
        }
    def _sets(self, data:dict={}, setAll:bool=False) -> None:
        """设置所有的数据
        Args:
            data (dict, optional): 需要设置的数据. Defaults to {}.
        Return:
            None
        """
        for key, ui in self.__uis.items():
            if hasattr(ui, "_set"):
                if setAll or key in data:
                    ui._set(data.get(key))
    def _get_widget(self, key:str="") -> QtWidgets.QWidget:
        """根据传入的key获取指定的 组件对象（非label）
        Args:
            key (str, optional): widget 的key. Defaults to "".
        Return:
            QtWidgets.QWidget: 返回的widget
        """
        return self.__uis.get(key)
    def __init_window_config(self) -> None:
        """初始化窗口配置
        Args:
            无
        Return:
            None
        """
        title = self.__data.get('title', '')
        icon = self.__data.get('icon', '')
        objectName = self.__data.get('objectName', '')
        size = self.__data.get('size', [400, 200])

        if title:
            self.__parent.setWindowTitle(title)
        if icon:
            self.__parent.setWindowIcon(QtGui.QIcon(icon))
        if objectName:
            self.__parent.setObjectName(objectName)
        if size:
            self.__parent.resize(*size)
    def __get_window_layout(self) -> QtWidgets.QWidget:
        """初始化窗口布局也就是主界面的整体布局
        Args:
            无
        Return:
            QtWidgets.QWidget : 返回一个布局对象
        """
        dataLayout = self.__data.get('layout', {})
        margin = dataLayout.get('margin', [10, 10, 10, 10])
        space = dataLayout.get('space', 10)
        objectName = dataLayout.get('objectName', "")
    
        qLayout = QtWidgets.QVBoxLayout()
        qLayout.setContentsMargins(*margin)
        qLayout.setSpacing(space)
        qLayout.setObjectName(objectName)
        return qLayout
    def __init_form_items(self, qLayout:QtWidgets.QWidget=None) -> None:
        """初始化表单中的项
        Args:
            qLayout (QtWidgets.QWidget, optional): 主布局. Defaults to None.
        Return:
            None
        """
        items = self.__data.get('items', [])
        for item in items:
            if not item: # item 不存在或者为空则认为是调整间距的space
                qLayout.addStretch(1)
                continue
            self.__init_form_item(item, qLayout)
        

        qLayout.addStretch(1)

    def __init_form_item(self, item:dict={}, qLayout:QtWidgets.QWidget=None) -> None:
        """初始化表单中的每一项
        Args:
            item (dict, optional): 每一项的数据. Defaults to {}.
            qLayout (QtWidgets.QWidget, optional): 主布局. Defaults to None.
        Return:
            None
        """
        type = item.get('type', '')
        if type in self.__TYPES:
            ui = self.__TYPES[type](item)
            qLayout.addWidget(ui)
            key = item.get('key')
            if key:
                self.__uis[key] = ui
        else:
            print("未知类型")
if __name__ == '__main__':
    # 测试例子
    app = QtWidgets.QApplication(sys.argv)
    dlg = QtWidgets.QDialog()
    uiConfigData = {
        "title": "测试", # window title 
        "icon": "icon.png", # window icon
        "objectName": "test", # window objectName
        "size": [400, 200], # window size
        "layout":{ # window 主布局
            "margin": [10, 10, 10, 10], # window 主布局的margin
            "space": 10,  # window 主布局的 Space
            "objectName": "qLayout", # window 主布局的 objectName
        },
        "items":[
            {
                "title":"text", # 标题 注意如果 typeParams 也设置了 title  那么优先取用 typeParams 中的title
                "must": True, # 是否必填 逻辑同上
                "key":"text",
                "type": "text",
                "typeParams": { # 不同的类型所需要的参数不同，由typeParams来传递
                    "title": "text",
                },
                "styleParams":{ # 控制样式的参数
                    "margin": [0, 0, 0, 0],
                    "space": 10,
                    "labWidth": 100,
                    "minWidth": 200,
                }
            },
            {
                "type": "file",
                "key":"caefile",
                "typeParams": { # 不同的类型所需要的参数不同，由typeParams来传递
                    "title": "file",
                    "fileType": "CAE Files (*.cae);;All Files (*)",
                },
                "styleParams":{ # 控制样式的参数
                    "margin": [0, 0, 0, 0],
                    "space": 10,
                    "labWidth": 100,
                }
            },
            {
                "type": "int",
                "key":"int",
                "typeParams": { # 不同的类型所需要的参数不同，由typeParams来传递
                    "title": "int",
                },
                "styleParams":{ # 控制样式的参数
                    "margin": [0, 0, 0, 0],
                    "space": 10,
                    "labWidth": 100,
                }
            },
            {
                "type": "float",
                "key":"float",
                "typeParams": { # 不同的类型所需要的参数不同，由typeParams来传递
                    "title": "float",
                },
                "styleParams":{ # 控制样式的参数
                    "margin": [0, 0, 0, 0],
                    "space": 10,
                    "labWidth": 100,
                }
            },
            {
                "type": "separator",
                "styleParams":{ # 控制样式的参数
                    "margin": [0, 0, 0, 0],
                }
            },
            {
                "type": "radios",
                "key":"radios",
                "title": "类型",
                "styleParams":{ # 控制样式的参数
                    "margin": [0, 0, 0, 0],
                    "space": 10,
                    "minWidth": 400,
                    
                },
                "typeParams":{
                    "data":[
                        {"title": "title1", "value": "value1"},
                        {"title": "title2", "value": "value2"},
                    ],
                    "onChanged": lambda value: print(value),   
                }
            },
            {
                "type": "select",
                "key":"select",
                "title": "场",
                "styleParams":{ # 控制样式的参数
                    "margin": [0, 0, 0, 0],
                    "space": 10,
                    "minWidth": 400,
                }
            },
            {
                "type": "radio",
                "key":"radio",
                "title": "类型",
                "styleParams":{ # 控制样式的参数
                    "margin": [0, 0, 0, 0],
                    "space": 10,
                    "minWidth": 400,
                }
                },
            {},
            {
                "type": "tools",
                "typeParams": { # 不同的类型所需要的参数不同，由typeParams来传递
                    "items": [
                        {
                            "title": "确定",
                            "objectName": "OK",
                            "action": lambda:print(ui._gets()), 
                        },
                        {
                            "title": "取消",
                            "objectName": "export",
                            "action":lambda: dlg.reject(),
                        }
                    ],
                },
                "styleParams":{ # 控制样式的参数
                    "margin": [0, 0, 0, 0],
                    "space": 10,
                }
            },
        ]
    }
    ui = UiCustomForm(uiConfigData)
    ui._setup_ui(dlg)
    dlg.adjustSize()
    dlg.show()
    sys.exit(app.exec())